﻿using System;
using System.Collections.Generic;
using System.Text;

using System.Drawing;

using System.Windows.Forms;
using System.Runtime.InteropServices;

using Microsoft.DirectX;

namespace NGE
{
    public class Game
    {
        #region 构造方法

        public Game()
            : this("noname")
        { }
        public Game(string name)
            : this(name, new Form())
        {
        }
        public Game(Control control)
            : this("noname", control)
        { }
        public Game(string name, Control control)
        {
            Timer = new Timer();

            Option = new Option();
            try
            {
                Option = (Option)Util.LoadObjectXML("option.xml", typeof(Option));
            }
            catch { }   
            if (control == null)
            {
                return;
            }

            Name = name;
            
            GameControl = control;
            if (GameControl is Form)
            {
                ((Form)GameControl).StartPosition = FormStartPosition.CenterScreen;
                ((Form)GameControl).Text = Name;
            }
            GameControl.Disposed += new EventHandler(OnGameControlDisposed);

            Graph = new Graph(this);

            Music = new Sound(this);
            Music.Volume = Option.Volume;

            Effect = new Sound(this);
            Effect.Volume = Option.Volume;

            Speech = new Sound(this);
            Speech.Volume = Option.Volume;

            Xinput = new Xinput(this);
            Keyboard = new Keyboard(this);
            Mouse = new Mouse(this);
            Inputer = new Inputer(this);

            MenuCOM = new MenuComponent("MenuCOM", this);
            MenuCOM.LoadMenu(new MENU.MsgBox(this));
            Mount(MenuCOM);

            //AnimationCOM = new AnimationComponent("AnimationCOM", this);
            //Mount(AnimationCOM);
        }

        void OnGameControlDisposed(object sender, EventArgs e)
        {
            Exit();
        }

        public bool IsFocused
        {
            get
            {
                return GameControl.Focused;
            }
        }
        bool isRunning = false;
        public Timer Timer;
        public Keyboard Keyboard;
        Xinput Xinput;
        Mouse Mouse;
        public Inputer Inputer;

        public Component GetComponent(string name)
        {
            for (int i = 0; i < Components.Count; i++)
            {
                if (Components[i].Name == name)
                {
                    return Components[i];
                }
            }
            return null;
        }



        public double LoopbackDuration;

        public string Name;
        public Control GameControl;
        public Option Option;

        public MenuComponent MenuCOM;
        //public AnimationComponent AnimationCOM;

        //public ClientComponent ClientCOM;

        //public SceneComponent SceneCOM;
        //public GUIComponent MenuCOM;

        public Graph Graph;
        public Sound Music;
        public Sound Effect;
        public Sound Speech;
        
        public List<Component> Components = new List<Component>();

        public double RunningTotalSeconds
        {
            get
            {
                return Timer.TotalSeconds;
            }
        }
        public double FPS
        {
            get
            {
                double fps = 1 / Timer.Seconds;
                fps = Math.Round(fps);
                //if (fps > FPSMax)
                //{
                //    if (RunningTotalSeconds > 1)
                //    {
                //        FPSMax = fps;
                //    }
                //}
                //if (fps < FPSMin)
                //{
                //    if (RunningTotalSeconds > 1)
                //    {
                //        FPSMin = fps;
                //    }
                //}
                return fps;
            }
        }

        #endregion

        void frame()
        {
            Timer.Record();
            Timer.Reset();
            
            if(Xinput!=null)
            Xinput.Heartbeat();
            if (Keyboard != null)
            Keyboard.Heartbeat();
            if (Mouse!= null)
            Mouse.Heartbeat();

            //if(Script!=null)
            //Script.Heartbeat();

            if (Graph != null)
            Graph.Clear();

            foreach (Component com in Components)
            {
                com.BasicHeartbeat();
                if (com.Enable)
                {
                    com.Heartbeat();
                }
                if (com.Visible)
                {
                    com.Show();
                }
            }

            if (Graph != null)
            Graph.Present();
        }

        //public bool IsOnline
        //{
        //    get
        //    {
        //        return ClientCOM.IsOnline;
        //    }
        //    set
        //    {
        //        ClientCOM.IsOnline = value;
        //    }
        //}

        //public void OpenPanelbox(string file, object arg)
        //{
        //    MenuCOM.Open(Option.GUIPath + file, arg);
        //}
        //public void OpenPanelbox(Panelbox pb, object arg)
        //{
        //    MenuCOM.Open(pb, arg);
        //}
        //public void ClosePanelbox()
        //{
        //    MenuCOM.Close();
        //}

        void goFullScreen()
        {
            if (GameControl is Form)
            {
                ((Form)GameControl).TopMost = true;
                HideWindowBorder();

                Graph.IsWindowed = false;
                Graph.Reset();
            }
        }
        void goWindowed()
        {
            if (GameControl is Form)
            {
                Graph.IsWindowed = true;
                Graph.Reset();

                ((Form)GameControl).TopMost = false;
                if (Option.IsShowWindowBorder)
                {
                    ShowWindowBorder();
                }
                else
                {
                    HideWindowBorder();
                }
            }
        }

        //public void SwitchFW()
        //{
        //    Option.IsFullScreen = !Option.IsFullScreen;
        //}     

        //public int GetCHRIndex(Vector3 loc)
        //{
        //    if (CHRs.Count == 0)
        //    {
        //        return -1;
        //    }
        //    int i = 0;
        //    foreach (Character chr in CHRs)
        //    {
        //        if (loc == chr.Location)
        //        {
        //            return i;
        //        }
        //        i++;
        //    }
        //    return -1;
        //}
        
        public void GoFullScreen()
        {
            Option.IsFullScreen = true;
        }
        public void GoWindowed()
        {
            Option.IsFullScreen = false;
        }
        public void Zoom(double x)
        {
            Graph.Zoom(x);
        }


        public void ShowWindowBorder()
        {
            if (GameControl is Form)
            {
                GameControl.Hide();
                ((Form)GameControl).FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
                GameControl.Show();
                Graph.Reset();
            }
        }
        public void HideWindowBorder()
        {
            if (GameControl is Form)
            {
                GameControl.Hide();
                ((Form)GameControl).FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
                GameControl.Show();
                Graph.Reset();
            }
        }

        public Component GetComponent(Type type)
        {
            foreach (Component com in Components)
            {
                if (com.GetType() == type)
                {
                    return com;
                }
            }
            return null;
        }
        public void Heartbeat()
        {
            //if (Devices.D3DDev.Disposed)
            //{
            //    return;
            //}
            frame();

            if (Graph == null)
            {
                return;
            }

            if (Option.IsFullScreen == Graph.IsWindowed)
            {
                if (Option.IsFullScreen)
                {
                    goFullScreen();
                }
                else
                {
                    goWindowed();
                }
                GameControl.Focus();
            }
            if (GameControl is Form)
            {
                if (Option.IsShowWindowBorder == false)
                {
                    if (((Form)GameControl).FormBorderStyle != FormBorderStyle.None)
                    {
                        HideWindowBorder();
                        GameControl.Focus();
                    }
                }
                else
                {
                    if (((Form)GameControl).FormBorderStyle == FormBorderStyle.None)
                    {
                        ShowWindowBorder();
                        GameControl.Focus();
                    }
                }
            }            
            //int result;
            //if (Devices.D3DDev.CheckCooperativeLevel(out result))
            //{
            //    //Okay to render
            //    try
            //    {
            //        frame();
            //    }
            //    catch (DeviceLostException)
            //    {
            //        Devices.D3DDev.CheckCooperativeLevel(out result);
            //    }
            //    catch (DeviceNotResetException)
            //    {
            //        Devices.D3DDev.CheckCooperativeLevel(out result);
            //    }
            //}
            //if (result == (int)ResultCode.DeviceLost)
            //{
            //    System.Threading.Thread.Sleep(500);    //Can't Reset yet, wait for a bit
            //}
            //else if (result == (int)ResultCode.DeviceNotReset)
            //{
            //    Devices.D3DDev.Reset(Devices.D3DDev.PresentationParameters);
            //}
        }
        public void Start()
        {
            //init();
            isRunning = true;

            Application.Idle += new EventHandler(OnApplicationIdle);

            if (GameControl is Form)
            {
                Application.Run((Form)GameControl);
            }

            //Devices.GameWindow.Show();
            //while (isRunning)
            //{
            //    Heartbeat();
            //    Application.DoEvents();
            //}
        }
        public void Pause()
        {
            isRunning = false;
        }
        public void Dispose()
        {
            //Devices.Dispose();
            //Keyboard.Dispose();
        }
        public void Exit()
        {
            isRunning = false;
            Dispose();
            Util.SaveObjectXML("option.xml", Option);
            Application.Exit();
        }
        public int Mount(Component component)
        {
            Components.Insert(0, component);
            return Components.Count - 1;
        }
        public void Unmount()
        {
            Components.Clear();
        }
        public void Unmount(Type type)
        {
            for (int i = 0; i < Components.Count; i++)
            {
                if (Components[i].GetType() == type)
                {
                    Unmount(i);
                    return;
                }
            }
        }
        public void Unmount(int i)
        {
            Components.RemoveAt(i);
        }

        #region 执行模板
        //public Queue<SystemMessage> SystemMessageQueue = new Queue<SystemMessage>();
        public SystemMessage SysMsg;
        /// <summary>
        /// AppIsIdle - Tests to see if there are messages that need processing, or if the
        ///   application is idle.
        /// </summary>
        bool ApplicationIsIdle
        {
            get
            {
                bool temp = WindowsAPI.PeekMessage(out SysMsg, IntPtr.Zero, 0, 0, 0);
                //SystemMessageQueue.Enqueue(SysMsg);
                return !temp;             
                //Keyboard.Push(SysMsg.msg);
                //Mouse.Push(SysMsg.msg);
            }
        }
        /// <summary>
        /// OnApplicationIdle - This function is to be bound to the application
        ///   idle event. As long as there are no messages waiting in the queue
        ///   it will call Heartbeat as fast as it can
        /// </summary>
        /// <param name="sender">not used</param>
        /// <param name="e">not used</param>
        void OnApplicationIdle(object sender, EventArgs e)
        {
            while (ApplicationIsIdle)
            {
                if (isRunning)
                    {
                        Heartbeat();
                    }
            }
        }
        #endregion
    }
}
